<template>
  <div class="form-input form-item" @click="handlerFormInputClick">
    <!-- 主内容 开始 -->
    <div
      class="f-wrap"
      :class="{
        'inputing-line': isIptFocus,
        'error-line': showBottomUnlegalMsg && showUnlegal
      }"
    >
      <!-- label -->
      <label v-if="label" class="f-label" @click="handlerLabelClick">
        <span class="require">
          <template v-if="isRequire && showRequire">
            *
          </template>
        </span>
        <span class="label">{{ label }}</span>
      </label>

      <!-- input框 -->
      <input
        class="f-ipt"
        :class="{
          'with-value': iptValue,
          'with-label': label,
          'with-icon': iconSrc,
          'with-right-label': rightLabel,
          picker: picker,
          'picker-disabled': pickerDisabled
        }"
        :type="type"
        v-model.trim="iptValue"
        :placeholder="placeholder"
        :disabled="disabled"
        @input="handlerIptInput"
        @click="handlerIptClick"
        @focus="handlerIptFocus"
        @blur="handlerIptBlur"
        ref="ipt"
      />

      <!-- icon -->
      <img
        v-if="iconSrc"
        class="icon"
        :style="{
          width: adaptSize.iconWidth + 'px'
        }"
        :src="iconSrc"
        @click.stop="handlerIconClick"
      />

      <!-- rightLabel: 右侧label -->
      <label
        v-if="rightLabel"
        class="f-label-right"
        @click.stop="handlerRightLabelClick"
      >
        {{ rightLabel }}
      </label>
    </div>
    <!-- 主内容 结束 -->

    <!-- 非法提示 -->
    <div
      class="unlegal-msg"
      :class="{
        show: showUnlegal && showBottomUnlegalMsg,
        'with-label': label
      }"
    >
      {{ vali.msg }}
    </div>
  </div>
</template>

<script>
export default {
  name: "formInput",
  props: {
    // 左侧的label描述
    label: {
      type: String,
      default: undefined
    },
    // 右侧的label描述
    rightLabel: {
      type: String,
      default: undefined
    },
    // 右侧图标
    iconSrc: {
      type: String,
      default: undefined
    },
    // icon width
    iconWidth: {
      type: Number,
      default: 17
    },
    // value值
    value: {
      default: undefined
    },
    // rules校验规则
    rules: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 输入类型
    type: {
      type: String,
      default: "text"
    },
    // placeholder
    placeholder: {
      type: String,
      default: undefined
    },
    // disabled
    disabled: {
      type: Boolean,
      default: false
    },
    // 是否是picker，在二次封装选择器时用到
    picker: {
      type: Boolean,
      default: false
    },
    // picker是否禁用，在二次封装选择器时用到
    pickerDisabled: {
      type: Boolean,
      default: false
    },
    // 是否显示底部错误信息
    showBottomUnlegalMsg: {
      type: Boolean,
      default: true
    },
    // 是否在必填的时候显示*
    showRequire: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      iptValue: "", // 当前输入的值
      // 当前验证状态
      vali: {
        status: false, // 校验结果，符合rules为true，不符合为false
        msg: "" // 校验信息
      },
      hadFormInputClick: false, // 当前formInput是否被点击过
      isIptFocus: false // 当前ipt是否获取焦点
    };
  },
  computed: {
    // 适配尺寸
    adaptSize() {
      // 当前屏幕宽度与设计稿宽度的比例
      const pxRadio = globalConfig.ui.pxRadio;
      return {
        iconWidth: this.iconWidth * pxRadio
      };
    },
    // 当前是否是必填项
    isRequire() {
      // 从rules中找是否包含require项
      return this.rules.find(rule => {
        return rule.regExp === "require";
      })
        ? true
        : false;
    },
    // 当前是否显示非法
    showUnlegal() {
      return (
        // 必须条件1：没有获得焦点的情况
        !this.isIptFocus &&
        // 必须条件2：值不符合校验规则
        !this.vali.status &&
        // 可选条件：formInput被点击过 || formInput没有点击过但是有值 || disabled无法改变值
        (this.hadFormInputClick ||
          (!this.hadFormInputClick && this.value) ||
          this.disabled)
      );
    }
  },
  watch: {
    // 监听value
    value: {
      handler(newVal) {
        // 更新iptValue
        this.iptValue = newVal;
        // 更新vali
        this.updateVali();
      },
      // 立即执行
      immediate: true
    },
    // 监听iptValue
    iptValue(newVal) {
      // 更新value
      this.$emit("input", newVal);
    }
  },
  created() {},
  methods: {
    // 验证
    updateVali() {
      const value = this.value;
      // 根据规则返回校验对象
      this.vali = this.getValiByRules(value);
      // 给父组件返回更新的校验结果
      this.$emit("updateVali", this.vali);
    },
    // 根据规则返回校验对象
    getValiByRules(val) {
      const vali = {
        status: true,
        msg: "校验通过"
      };
      // 找到输入项不符合的第一个校验规则
      const firstUnlegalRule = this.rules.find(rule => {
        // 取得regExp验证规则
        let regExp = rule.regExp;
        if (typeof regExp === "function") {
          // 方法校验
          return !regExp(val);
        } else if (typeof regExp === "string") {
          // string类型：为regExp.js中约定的验证规则，则去取对应的正则表达式
          return !utils.regExp.get(regExp).test(val);
        } else {
          // 普通正则表达式
          return !regExp.test(val);
        }
      });

      if (
        // 找到输入项不符合的第一个校验规则
        firstUnlegalRule &&
        // 排除不必须并且没有值的情况
        !(!this.isRequire && !val)
      ) {
        vali.status = false;
        vali.msg = firstUnlegalRule.msg;
      }

      return vali;
    },

    // 处理整个formInput click
    handlerFormInputClick() {
      // 设置formInput被点击过
      this.hadFormInputClick = true;
      this.$emit("formInputClick");
    },
    // 处理label点击
    handlerLabelClick() {
      this.$refs.ipt.focus();
      this.$emit("labelClick");
    },

    // 处理ipt click
    handlerIptClick() {
      this.$emit("iptClick");
    },
    // 处理ipt input
    handlerIptInput() {
      this.$emit("iptInput");
    },
    // 处理ipt focus
    handlerIptFocus() {
      this.isIptFocus = true;
      this.$emit("iptFocus");
    },
    // 处理ipt blur
    handlerIptBlur() {
      this.isIptFocus = false;
      // ios键盘bug修复
      utils.ui.handlerIOSKeyboardHidden();
      this.$emit("iptBlur");
    },

    // 处理icon点击
    handlerIconClick() {
      this.$emit("iconClick");
    },
    // 处理rightLabel点击
    handlerRightLabelClick() {
      this.$emit("rightLabelClick");
    }
  }
};
</script>

<style lang="scss" scoped>
@import "@/assets/css/common/form.scss";
.f-wrap {
  // input框
  .f-ipt {
    @include lineheight-height(20px);
    @include reset-input;
    @include overflow-emphasis;
    flex: 1;
    letter-spacing: 1px;
    font-size: $font-size;
    color: $font-color;
    // placeholder样式重写
    &::placeholder {
      font-size: $font-size;
      letter-spacing: 1px;
      color: $font-color-dark;
    }
    // disabled样式重写
    &:disabled {
      background-color: transparent;
      opacity: 1;
      // 输入框 disabled
      &:not(.picker) {
        color: $font-color-disabled;
        -webkit-text-fill-color: $font-color-disabled;
      }
      // picker 有值--ios input disabled自带透明颜色，需重写
      &.picker.with-value {
        color: $font-color;
        -webkit-text-fill-color: $font-color;
      }
      // picker disabled
      &.picker.picker-disabled {
        color: $font-color-disabled;
        -webkit-text-fill-color: $font-color-disabled;
      }
    }
    // 带label字右对齐
    &.with-label {
      text-align: right;
    }
    // 带icon
    &.with-icon {
      margin-right: 10px;
    }
    // 带右侧label
    &.with-right-label {
      margin-right: 10px;
    }
  }
}

// 错误信息提示
.unlegal-msg {
  width: 100%;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  font-size: $font-size;
  color: $color-error;
  height: 0;
  overflow: hidden;
  transition: height 0.2s ease-out;
  &.show {
    height: 30px;
  }
  // 带label字右对齐
  &.with-label {
    justify-content: flex-end;
  }
}
</style>
